package com.plan.service.card.impl;

import com.plan.base.config.property.AppProperty;
import com.plan.base.constant.BaseCode;
import com.plan.base.entity.Result;
import com.plan.base.util.DateUtil;
import com.plan.controller.card.request.CompleteAllReq;
import com.plan.controller.card.request.CopyHistoryDayPlanReq;
import com.plan.controller.card.request.DayPlanListReq;
import com.plan.controller.card.response.DayPlanListRes;
import com.plan.controller.card.response.DayPlanMainInfoRes;
import com.plan.controller.user.response.UserVO;
import com.plan.dao.mapper.card.CardMapper;
import com.plan.dao.mapper.card.DayPlanMapper;
import com.plan.dao.mapper.card.DayPlanStatMapper;
import com.plan.dao.service.card.DayPlanDaoService;
import com.plan.entity.card.Card;
import com.plan.entity.card.DayPlan;
import com.plan.entity.card.DayPlanStat;
import com.plan.entity.card.PointLog;
import com.plan.enums.DayPlanStatusEnum;
import com.plan.enums.DelFlagEnum;
import com.plan.enums.PointTypeEnum;
import com.plan.service.card.DayPlanService;
import com.plan.service.card.TeamService;
import com.plan.service.uesr.AuthManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class DayPlanServiceImpl implements DayPlanService {
    @Resource
    private TeamService teamService;
    @Resource
    private DayPlanStatMapper dayPlanStatMapper;
    @Resource
    private DayPlanMapper dayPlanMapper;
    @Resource
    private CardMapper cardMapper;
    @Resource
    private DayPlanDaoService dayPlanDaoService;
    @Resource
    private AuthManager authManager;
    @Resource
    private AppProperty appProperty;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Long> insert(DayPlan plan) {
        // 累计任务数量
        DayPlanStat dayStat = dayPlanStatMapper.getOneByYearMonthDay(plan.getTeamId(), plan.getCardId(), plan.getYearMonthDay());
        if (dayStat == null) {
            dayStat = new DayPlanStat();
            dayStat.setCardId(plan.getCardId());
            dayStat.setTeamId(plan.getTeamId());
            dayStat.setYearMontDay(plan.getYearMonthDay());
            dayStat.setTaskNum(1);
            dayStat.setGetPoint(plan.getAwardPoint());
        } else {
            dayStat.setGetPoint(dayStat.getGetPoint() + plan.getAwardPoint());
            dayStat.setTaskNum(dayStat.getTaskNum() + 1);
            if (dayStat.getTaskNum() > appProperty.getDayPlanMax()) {
                return Result.fail(BaseCode.DAY_PLAN_LIMIT_ERROR);
            }
        }
        if (plan.getAwardPoint() < 0) {
            // 惩罚直接变成开始，插入成功后直接走完成逻辑
            plan.setStatus(DayPlanStatusEnum.STARTED.getStatus());
        }
        Long id = dayPlanDaoService.insertDayPlan(plan, dayStat);
        if (plan.getAwardPoint() < 0) {
            UserVO user = authManager.getUserByIdFromCache(plan.getCreatorId());
            this.complete(id, user);
        }
        return Result.ok(id);
    }

    @Override
    public Result<Long> start(Long dayPlanId, UserVO vo) {
        DayPlan old = dayPlanMapper.getOneById(dayPlanId);
        if (old == null) {
            return Result.fail(BaseCode.DATA_NOT_EXIST);
        }
        if (old.getStatus() != DayPlanStatusEnum.NEW.getStatus()) {
            return Result.fail(BaseCode.ILLEGAL_OPERATION);
        }
        if (!teamService.isUserInTeam(old.getTeamId(), vo.getId())) {
            return Result.fail(BaseCode.ILLEGAL_OPERATION);
        }
        DayPlan update = new DayPlan();
        update.setStatus(DayPlanStatusEnum.STARTED.getStatus());
        update.setUpdaterId(vo.getId());
        update.setId(dayPlanId);
        dayPlanDaoService.update(update, null);
        return Result.ok();
    }

    @Override
    public Result<Long> complete(Long dayPlanId, UserVO vo) {
        DayPlan old = dayPlanMapper.getOneById(dayPlanId);
        if (old == null) {
            return Result.fail(BaseCode.DATA_NOT_EXIST);
        }
        if (old.getStatus() != DayPlanStatusEnum.STARTED.getStatus()) {
            log.warn("当前状态不允许再完成，oldStatus={}", old.getStatus());
            return Result.fail(BaseCode.ILLEGAL_OPERATION);
        }
        if (!teamService.isUserInTeam(old.getTeamId(), vo.getId())) {
            log.warn("非法操作，oldTeamId={},userId={}", old.getTeamId(), vo.getId());
            return Result.fail(BaseCode.ILLEGAL_OPERATION);
        }
        this.complete(old, vo.getId());
        return Result.ok();
    }

    @Override
    public Result<Long> delete(Long dayPlanId, Long userId) {
        DayPlan old = dayPlanMapper.getOneById(dayPlanId);
        if (old == null) {
            return Result.ok();
        }
        if (old.getStatus() == DayPlanStatusEnum.COMPLETED.getStatus()) {
            return Result.fail(BaseCode.ILLEGAL_OPERATION);
        }
        if (!teamService.isUserInTeam(old.getTeamId(), userId)) {
            return Result.fail(BaseCode.ILLEGAL_OPERATION);
        }
        DayPlanStat dayStat = dayPlanStatMapper.getOneByYearMonthDay(old.getTeamId(), old.getCardId(), old.getYearMonthDay());
        dayStat.setTaskNum(dayStat.getTaskNum() - 1);
        dayStat.setGetPoint(dayStat.getGetPoint() - old.getAwardPoint());
        if (dayStat.getTaskNum() == 0) {
            dayPlanDaoService.delete(dayPlanId, null, dayStat.getId());
        } else {
            dayPlanDaoService.delete(dayPlanId, dayStat, null);
        }
        return Result.ok();
    }

    @Override
    public List<DayPlanListRes> list(DayPlanListReq req) {
        return dayPlanMapper.getList(req);
    }

    @Override
    public DayPlanMainInfoRes getDayPlanListForIndexPage(DayPlanListReq req) {
        DayPlanMainInfoRes res = new DayPlanMainInfoRes();
        List<DayPlanListRes> list = dayPlanMapper.getList(req);
        DayPlanStat dayPlanStat = dayPlanStatMapper.getOneByYearMonthDay(req.getTeamId(), req.getCardId(), req.getYearMonthDay());
        if (dayPlanStat != null) {
            res.setTodayPoint(dayPlanStat.getGetPoint());
        } else {
            res.setTodayPoint(0);
        }
        Card card = cardMapper.selectOneById(req.getTeamId(), req.getCardId());
        if (card != null) {
            res.setRemainPoint(card.getRemainPoint());
        } else {
            res.setRemainPoint(0);
        }
        res.setPlanList(list);
        return res;
    }

    @Override
    public Result<String> copyoneDayPlanList(CopyHistoryDayPlanReq req, UserVO user) {
        DayPlanStat history = dayPlanStatMapper.getOneByYearMonthDay(req.getTeamId(), req.getCardId(), req.getYearMonthDay());
        if (history == null) {
            return Result.fail(BaseCode.DATA_NOT_EXIST);
        }
        int now = DateUtil.getYearMonthDayFromDate(new Date());
        history.setId(null);
        history.setYearMontDay(now);

        DayPlanListReq dayPlanListReq = new DayPlanListReq();
        dayPlanListReq.setTeamId(req.getTeamId());
        dayPlanListReq.setCardId(req.getCardId());
        dayPlanListReq.setYearMonthDay(req.getYearMonthDay());
        List<DayPlanListRes> list = dayPlanMapper.getList(dayPlanListReq);
        if (CollectionUtils.isEmpty(list)) {
            return Result.fail(BaseCode.DATA_NOT_EXIST);
        }

        // 今天存在就不复制了
        DayPlanStat todayStat = dayPlanStatMapper.getOneByYearMonthDay(req.getTeamId(), req.getCardId(), now);
        Date start = new Date();
        if (todayStat != null) {
//            start = DateUtil.addDays(start, 1);
//            req.setDays(req.getDays() - 1);
            return Result.fail(BaseCode.PLAN_EXISTS);
        }

        // 默认每天15个去初始化数组
        List<DayPlan> copyList = new ArrayList<>(req.getDays() * 15);
        List<Integer> dayList = new ArrayList<>(req.getDays());
        for (int i = 0; i < 1; i++) {
            Date belongDate = DateUtil.addDays(start, i);
            int belongDay = DateUtil.getYearMonthDayFromDate(belongDate);
            dayList.add(belongDay);
            for (DayPlanListRes d : list) {
                DayPlan plan = new DayPlan();
                plan.setName(d.getName());
                plan.setTeamId(req.getTeamId());
                plan.setCardId(req.getCardId());
                plan.setYearMonthDay(belongDay);
                plan.setCreatorId(user.getId());
                plan.setUpdaterId(user.getId());
                plan.setDelFlag(DelFlagEnum.NORMAL.getType());
                plan.setStatus(DayPlanStatusEnum.NEW.getStatus());
                plan.setAwardPoint(d.getAwardPoint());
                copyList.add(plan);
            }
        }

        // 检查要复制的日期是否已经存在了，存在则先删除再插入：直接先删除一遍再插入
        dayPlanDaoService.copyOneDayPlanList(history, copyList);
        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> completeForIdList(CompleteAllReq req, UserVO user) {
        req.setUpdaterId(user.getId());
        dayPlanDaoService.completeForIdList(req);
        for (Long dayPlanId : req.getIdList()) {
            DayPlan old = dayPlanMapper.getOneById(dayPlanId);
            this.complete(old, user.getId());
        }
        return Result.ok();
    }

    private void complete(DayPlan old, Long userId) {
        Card card = cardMapper.selectOneById(old.getTeamId(), old.getCardId());
        Card updateCard = new Card();
        updateCard.setId(card.getId());
        updateCard.setTeamId(old.getTeamId());
        updateCard.setRemainPoint(card.getRemainPoint() + old.getAwardPoint());
        updateCard.setTotalPoint(card.getTotalPoint() + old.getAwardPoint());
        updateCard.setVersion(card.getVersion());
        updateCard.setUpdaterId(userId);

        PointLog pointLog = new PointLog();
        pointLog.setPoint(old.getAwardPoint());
        pointLog.setTeamId(old.getTeamId());
        pointLog.setCardId(old.getCardId());
        pointLog.setEventName(old.getName());
        pointLog.setCreatorId(userId);
        pointLog.setUpdaterId(userId);
        pointLog.setPointType(PointTypeEnum.COMPLETE_PLAN.getType());
        pointLog.setDelFlag(DelFlagEnum.NORMAL.getType());

        DayPlan update = new DayPlan();
        update.setStatus(DayPlanStatusEnum.COMPLETED.getStatus());
        update.setUpdaterId(userId);
        update.setId(old.getId());
        dayPlanDaoService.complete(update, updateCard, pointLog);
    }

}
